﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Configuration;
using System.Data.SQLite;
using System.Threading;
using System.IO;
using System.Windows.Forms;
using TwinCAT.Ads;
using log4net;
using System.Xml;
using TwinCAT.Ads.TypeSystem;
using System.Data;

namespace ADS2Excel
{
    struct DataADS
    {
        public string name;
        public int[] data;
    };

    struct AutomationData
    {
        public uint TotalNum;
        public uint AutomationNum;
        public uint InterventionLNum;
        public uint InterventionRNum;
    }
    public partial class MainForm : Form 
    {

        private static log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

        private bool isExit;
        private TcAdsClient tcClient;
   
        private TcAdsSymbolInfoLoader symbolLoader;

        private List<DataADS> DataADS_L = new List<DataADS>();
        private List<DataADS> DataADS_R = new List<DataADS>();

        private AutomationData ad = new AutomationData();

        private Dictionary<string, short[]> tempdata;
        private bool Flag_GEMEI_END_L, Flag_GEMEI_END_L_last;
        private bool Flag_GEMEI_END_R, Flag_GEMEI_END_R_last;
        private bool Flag_Direction;
        private ushort ChooseStep;
        private ushort _location_Shearer;
        public ushort Location_Shearer
        {
            get { return _location_Shearer; }
            set
            {
                if(_location_Shearer != value)
                {
                    OnLocationShearerChangedEvent(value);
                }
                _location_Shearer = value;
            }
        }

        public delegate void LocationShearerChangedDelegate(ushort value);
        //与委托相关联的事件
        public event LocationShearerChangedDelegate OnLocationShearerChangedEvent;        
       
        //具体委托函数
        void WhenLocationShearerChanged(ushort value)
        {
            Console.WriteLine("Loaction is Changed:{0:D3}", value);
            bw.RunWorkerAsync("MJWZ");
        }

        private string amsid = ConfigurationManager.AppSettings["AMSID"];
        private static int N = Convert.ToInt32(ConfigurationManager.AppSettings["Number"]);
      
        BackgroundWorker bw = new BackgroundWorker();

        private ModbusNode mbSlave;

        public MainForm()
        {
            InitializeComponent();
            this.Load += new EventHandler(MainForm_Load);
            this.Resize += new EventHandler(MainForm_Resize);
            this.FormClosing += new FormClosingEventHandler(MainForm_Closing);
            this.btnSaveDataL.Click += new EventHandler(btnSaveDataL_Click);
            this.btnSaveDataR.Click += new EventHandler(btnSaveDataR_Click);

            bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_InsertData_RunWorkerCompleted);
            bw.DoWork += new DoWorkEventHandler(bw_SaveData);
            //bwR.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_InsertData_RunWorkerCompleted);

            isExit = false;

            var listsy_R = SymbolConfig.GetSymbolADS(SymbolConfig.Flag_Direction.R);
            var listsy_L = SymbolConfig.GetSymbolADS(SymbolConfig.Flag_Direction.L);
            foreach (var ll in listsy_L)
            {
                DataADS_L.Add(new DataADS { name = ll.SymbolADSName, data = new int[300] });
            }
            foreach (var lr in listsy_R)
            {
                DataADS_R.Add(new DataADS { name = lr.SymbolADSName, data = new int[300] });
            }

            //创建SQLite3数据库
            SQLite3.CreateTables();

            tempdata = new Dictionary<string, short[]>
            {   {"SJCG_Z",new short[300]},
                {"YCCG_Z",new short[300]},
                {"SJWD_Z",new short[300]},
                {"YCWD_Y",new short[300]},
                {"SJCG_Y",new short[300]},
                {"YCCG_Y",new short[300]},
                {"SJWD_Y",new short[300]},
                {"YCWD_Z",new short[300]},
                {"SJCG" ,new short[300]},
                {"SJWD" ,new short[300]}
            };

            //开机读取
            ad.TotalNum = SettingsNum.Default.TotalNum;
            ad.AutomationNum = SettingsNum.Default.AutomationNum;
            ad.InterventionLNum = SettingsNum.Default.InterventionLNum;
            ad.InterventionRNum = SettingsNum.Default.InterventionRNum;

            OnLocationShearerChangedEvent += WhenLocationShearerChanged;
        }


        private void MainForm_Load(object sender ,System.EventArgs e)
        {
            //启动最小化隐藏
            this.WindowState = FormWindowState.Minimized;
            this.Visible = false;

            //创建Excel文件
            ExcelHelper.CreateExcelFile(SymbolConfig.Flag_Direction.L, DataADS_L);
            ExcelHelper.CreateExcelFile(SymbolConfig.Flag_Direction.R, DataADS_R);
            ExcelHelper.CreateExcelFile("煤机位置");

            tcClient = new TcAdsClient();
            tcClient.Connect(amsid, 801);

            symbolLoader = tcClient.CreateSymbolInfoLoader();

            //启动结束标志位处理线程
            Thread tHandlerEndFlag = new Thread(new ThreadStart(HandlerEndFlag));
            tHandlerEndFlag.Start();
            log.Debug("tHandlerEndFlag.Start();");

            mbSlave = new ModbusNode(1,2502,"PLC");
            mbSlave.start();
        }

        private void MainForm_Resize(object sender, EventArgs e)
        {
            if (this.WindowState == FormWindowState.Minimized)
            {
                this.Visible = false;
                this.notifyIcon1.Visible = true;
            }
        }

        private void notifyIcon1_MouseDoubleClick(object sender, MouseEventArgs e)
        {
            this.Visible = true;
            this.WindowState = FormWindowState.Normal;
            this.Show();
        }
        private void GetEndFlag()
        {
            Flag_GEMEI_END_L_last = Flag_GEMEI_END_L;
            Flag_GEMEI_END_R_last = Flag_GEMEI_END_R;
            try
            {
                int hResultEndL = tcClient.CreateVariableHandle(".GEMEI_END_L");
                int hResultEndR = tcClient.CreateVariableHandle(".GEMEI_END_R");
                int hLocation = tcClient.CreateVariableHandle(".MJWZ");
                int hRun_Direction = tcClient.CreateVariableHandle(".FX_L");
                int hChoose_Step = tcClient.CreateVariableHandle(".choose_step");

                Flag_GEMEI_END_L = (bool)tcClient.ReadAny(hResultEndL, typeof(Boolean));
                Flag_GEMEI_END_R = (bool)tcClient.ReadAny(hResultEndR, typeof(Boolean));
                Location_Shearer = (ushort)tcClient.ReadAny(hLocation, typeof(ushort));
                Flag_Direction = (bool)tcClient.ReadAny(hRun_Direction, typeof(Boolean));
                ChooseStep = (ushort)tcClient.ReadAny(hChoose_Step, typeof(ushort));



                int hSJCG = tcClient.CreateVariableHandle(".SHIJICAIGAO");
                AdsStream ds = new AdsStream(2*N+2);
                BinaryReader br = new BinaryReader(ds);

                tcClient.Read(hSJCG, ds);
                ds.Position = 0;
                for (int i = 0; i < N + 1; i++)
                {
                    tempdata["SJCG"][i] = br.ReadInt16();
                }
                int hSJWD = tcClient.CreateVariableHandle(".SJWDL");
                AdsStream ds1 = new AdsStream(2 * N + 2);
                BinaryReader br1 = new BinaryReader(ds1);

                tcClient.Read(hSJWD, ds1);
                ds.Position = 0;
                for (int i = 0; i < N + 1; i++)
                {
                    tempdata["SJWD"][i] = br1.ReadInt16();
                }

                               
                mbSlave._dataStore.HoldingRegisters[10001] = Location_Shearer;
                mbSlave._dataStore.HoldingRegisters[10002] = ChooseStep;
                mbSlave._dataStore.CoilDiscretes[1] = Flag_Direction;
               
                log.Debug("Flag_L:" + Flag_GEMEI_END_L.ToString()
                    + " , Flag_L_last:" + Flag_GEMEI_END_L_last.ToString()
                    + " , Flag_R:" + Flag_GEMEI_END_R.ToString()
                    + " , Flag_R_last:" + Flag_GEMEI_END_R_last.ToString());
                
            }
            catch (Exception err)
            {
               
                //ResultAppendText(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")+"GetEndFlag Error," + err.Message + "\r\n"); ;
                log.Debug(err.ToString());
                Console.WriteLine(err.ToString());
                //if (ErrorCount > 10)
                //{
                //    log.Debug("ErrorCount > 5");
                //    ResultAppendText(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "ErrorCount > 5 App Exit");
                //    Thread.Sleep(2000);
                //    System.Environment.Exit(0);
                //}
                //Thread.Sleep(1000);
            }
        }

        private void HandlerEndFlag()
        {
            while(!isExit)
            {
                GetEndFlag();
                
                if (Flag_GEMEI_END_L && !Flag_GEMEI_END_L_last)
                {
                    ResultAppendText(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss ") + ": 捕获到割煤完成标志位-左(Cycle)\r\n");
                    log.Info("捕获到割煤完成标志位 - 左(Cycle)");                 
                    bw.RunWorkerAsync("RESULT_L");                    
                }
                else if (Flag_GEMEI_END_R && !Flag_GEMEI_END_R_last)
                {
                    ResultAppendText(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss ") + ": 捕获到割煤完成标志位-右(Cycle)\r\n");
                    log.Info("捕获到割煤完成标志位 - 右(Cycle)");
                    bw.RunWorkerAsync("RESULT_R");
                }

                DataSet ds_1 = SQLite3.SelectDB("SJCG_Z");
                DataSet ds_2 = SQLite3.SelectDB("YCCG_Z");
                DataSet ds_3 = SQLite3.SelectDB("SJWD_Z");
                DataSet ds_4 = SQLite3.SelectDB("YCWD_Y");
                DataSet ds_5 = SQLite3.SelectDB("SJCG_Y");
                DataSet ds_6 = SQLite3.SelectDB("YCCG_Y");
                DataSet ds_7 = SQLite3.SelectDB("SJWD_Y");
                DataSet ds_8 = SQLite3.SelectDB("YCWD_Z");
                for (int i = 1; i <= 250; i++)
                {
                    if (ds_1.Tables[0].Rows.Count > 0)
                        mbSlave._dataStore.HoldingRegisters[i] = (ushort)Convert.ToInt16(ds_1.Tables[0].Rows[0][i]);
                    if (ds_2.Tables[0].Rows.Count > 0)
                        mbSlave._dataStore.HoldingRegisters[i+500] = (ushort)Convert.ToInt16(ds_2.Tables[0].Rows[0][i]);
                    if (ds_3.Tables[0].Rows.Count > 0)
                        mbSlave._dataStore.HoldingRegisters[i + 1000] = (ushort)Convert.ToInt16(ds_3.Tables[0].Rows[0][i]);
                    if (ds_4.Tables[0].Rows.Count > 0)
                        mbSlave._dataStore.HoldingRegisters[i+1500] = (ushort)Convert.ToInt16(ds_4.Tables[0].Rows[0][i]);
                    if (ds_5.Tables[0].Rows.Count > 0)
                        mbSlave._dataStore.HoldingRegisters[i+2000] = (ushort)Convert.ToInt16(ds_5.Tables[0].Rows[0][i]);
                    if (ds_6.Tables[0].Rows.Count > 0)
                        mbSlave._dataStore.HoldingRegisters[i+2500] = (ushort)Convert.ToInt16(ds_6.Tables[0].Rows[0][i]);
                    if (ds_7.Tables[0].Rows.Count > 0)
                    {  
                        mbSlave._dataStore.HoldingRegisters[i + 3000] = (ushort)Convert.ToInt16(ds_7.Tables[0].Rows[0][i]);
                    }
                    if (ds_8.Tables[0].Rows.Count > 0)
                        mbSlave._dataStore.HoldingRegisters[i+3500] = (ushort)Convert.ToInt16(ds_8.Tables[0].Rows[0][i]);

                    mbSlave._dataStore.HoldingRegisters[i + 5000] = (ushort)tempdata["SJCG"][i-1];
                    mbSlave._dataStore.HoldingRegisters[i + 5500] = (ushort)tempdata["SJWD"][i-1];
                }
                Console.WriteLine("{0:F}  :Loaction_Shearer is  {1:D3}", DateTime.Now,Location_Shearer);
                Console.WriteLine("{0:F}  :Step is  {1:D3}", DateTime.Now, ChooseStep);
                Thread.Sleep(1000);
            }
                      
        }

        private  void MainForm_Closing(object sender,System.EventArgs e)
        {
            isExit = true;
            Thread.Sleep(200);
            tcClient.Dispose();
            mbSlave.stop();
        }

        public void Insert_Data_ToDB(string now, params string[] tableName)
        {
            SQLiteConnection conn = new SQLiteConnection(SQLite3.dbPath);//创建数据库实例，指定文件位置  
            conn.Open();//打开数据库，若文件不存在会自动创建

            SQLiteTransaction tran = conn.BeginTransaction();//实例化一个事务  

            SQLiteCommand cmdTemp = new SQLiteCommand(conn);
            cmdTemp.Transaction = tran;
            foreach (var item in tableName)
            {
                cmdTemp.CommandText = SQLite3.GenerateInsertSQL(item, N);
                cmdTemp.Parameters.AddRange(GenerateSQLiteParameter(now, item, N));
                cmdTemp.ExecuteNonQuery();
            }

            tran.Commit();//提交
            conn.Close();
        }
        public SQLiteParameter[] GenerateSQLiteParameter(string now, string table, int num)
        {
            SQLiteParameter[] sqlparamenter = new SQLiteParameter[num + 1];
            sqlparamenter[0] = new SQLiteParameter("@time", now);
            string s = "";
            string name = "";
            for (int i = 1; i <= num; i++)
            {
                s = Convert.ToString(i);
                name = table + s;
                //if (table.Equals("SJCG_Z"))
                //{
                //    sqlparamenter[i] = new SQLiteParameter("@" + name, tempdata["SJCG_Z"][i - 1]);
                //}
                //else if (table.Equals("RESULT_L"))
                //{
                //    sqlparamenter[i] = new SQLiteParameter("@" + name, V_ResultL[i]);
                //}
                //else if (table.Equals("RESULT_R"))
                //{
                //    sqlparamenter[i] = new SQLiteParameter("@" + name, V_ResultR[i]);
                //}
                sqlparamenter[i] = new SQLiteParameter("@" + name, tempdata[table][i - 1]);
            }
            return sqlparamenter;
        }
        //rhTxtResult跨线程委托追加文字
        public delegate void AppedText(string resultText);

        public void ResAppedText(string resultText)
        {
            this.rhTxtResult.AppendText(resultText);
        }
        public void ResultAppendText(string resultText)
        {
            if (rhTxtResult.InvokeRequired)
            {
                this.Invoke(new AppedText(ResAppedText), resultText);               
            }
            else
            {
                this.rhTxtResult.AppendText(resultText);
            }
        }

        private void btnReadSymbolInfo_Click(object sender, EventArgs e)
        {

            TcAdsSymbolInfo symbol = symbolLoader.GetFirstSymbol(true);
            while (symbol != null)
            {
                ResultAppendText(symbol.Name+"\r\n");
                symbol = symbol.NextSymbol;
                //symbol = symbol.SubSymbols;
            }
        }

        private void btnGetValues_Click(object sender, EventArgs e)
        {
            
        }

        private void GetData(SymbolConfig.Flag_Direction f)
        {
             List<DataADS> lDataADS =null;
           
            try
            {
                int num = (N + 1) * 2;
                if (f==SymbolConfig.Flag_Direction.L)
                {
                    lDataADS = DataADS_L;
                }else
                {
                    lDataADS = DataADS_R;
                }
                // AdsStream which gets the data
                foreach (var ll in lDataADS)
                {
                    int handler = tcClient.CreateVariableHandle(ll.name);
                    AdsStream ds = new AdsStream(num);
                    BinaryReader br = new BinaryReader(ds);

                    tcClient.Read(handler, ds);
                    ds.Position = 0;
                    for (int i = 0; i < N + 1; i++)
                    {
                        ll.data[i] = br.ReadInt16();
                    }

                    if (f == SymbolConfig.Flag_Direction.L)
                    {

                        for (int i = 0; i < 250; i++)
                        {
                            if (ll.name.Equals(".SHIJICAIGAO"))
                            {
                                tempdata["SJCG_Z"][i] = (short)ll.data[i];
                            }
                            else if (ll.name.Equals(".Result_L"))
                            {
                                tempdata["YCCG_Z"][i] = (short)ll.data[i];
                            }
                            else if (ll.name.Equals(".SJWDL"))
                            {
                                tempdata["SJWD_Z"][i] = (short)ll.data[i];
                            }
                            else if (ll.name.Equals(".ResultWodi_R"))
                            {
                                tempdata["YCWD_Y"][i] = (short)ll.data[i];
                            }
                        }
                    }
                    else
                    {
                        for (int i = 0; i < 250; i++)
                        {
                            if (ll.name.Equals(".SHIJICAIGAO"))
                            {
                                tempdata["SJCG_Y"][i] = (short)ll.data[i];
                            }
                            else if (ll.name.Equals(".Result_R"))
                            {
                                tempdata["YCCG_Y"][i] = (short)ll.data[i];
                            }
                            else if (ll.name.Equals(".SJWDL"))
                            {
                                tempdata["SJWD_Y"][i] = (short)ll.data[i];
                            }
                            else if (ll.name.Equals(".ResultWodi_L"))
                            {
                                tempdata["YCWD_Z"][i] = (short)ll.data[i];
                            }
                        }
                    }
                }

            }
            catch (Exception err)
            {
                //MessageBox.Show(err.Message);
                ResultAppendText("GetData Error," + err.Message+"\r\n");
            }
        }

        
        private void btnSaveDataL_Click(object sender, EventArgs e)
        {
            ResultAppendText(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")+ ": Save Data (L)Testing:\r\n");
            if (Flag_GEMEI_END_L)
            {  Flag_GEMEI_END_L = false; }
            else
            { Flag_GEMEI_END_L = true; }
            bw.RunWorkerAsync("RESULT_L");
            ResultAppendText(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + ": Save Data (L)Testing End:\r\n");
        }

        private void btnSaveDataR_Click(object sender, EventArgs e)
        {
            ResultAppendText(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + ": Save Data (R)Testing:\r\n");
            if (Flag_GEMEI_END_R)
            { Flag_GEMEI_END_R = false; }
            else
            { Flag_GEMEI_END_R = true; }
            bw.RunWorkerAsync("RESULT_R");
            ResultAppendText(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + ": Save Data (R)Testing End:\r\n");
        }

        public void Insert_L_Data(string nowtime)
        {
            ResultAppendText("Insert_L_Data：开始存储左数据\r\n");
            ExcelHelper.SaveToXlsXL(nowtime,DataADS_L);
        }

        public void Insert_R_Data(string nowtime)
        {
            ResultAppendText("Insert_R_Data：开始存储右数据\r\n");
            ExcelHelper.SaveToXlsXR(nowtime, DataADS_R);
        }
 

        //数据保存完成后，在主界面显示完成信息
        void bw_InsertData_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            ResultAppendText(e.Result.ToString());
            log.Info(e.Result.ToString());
        }

        //保存数据
        void bw_SaveData(object sender, DoWorkEventArgs e)
        {
            //获取参数
            string st = (string)e.Argument;
            string now = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
            Thread.Sleep(100); // 延时100ms后
           
            if (st == "RESULT_R")
            {
                GetData(SymbolConfig.Flag_Direction.R);
                Insert_R_Data(now);
                Insert_Data_ToDB(now, new string[4] { "SJCG_Y", "YCCG_Y", "SJWD_Y", "YCWD_Z" });
                e.Result = now + ": 实际采高-预测采高右数据存储完成\r\n";
            }
            else if (st == "RESULT_L")
            {
                GetData(SymbolConfig.Flag_Direction.L);
                Insert_L_Data(now);
                Insert_Data_ToDB(now, new string[4] { "SJCG_Z", "YCCG_Z", "SJWD_Z", "YCWD_Y" });
                e.Result = now + ": 实际采高-预测采高左数据存储完成\r\n";
            }
            else if (st == "MJWZ")
            {
                if(Location_Shearer != 0)
                {
                    ExcelHelper.SaveToXlsXLocation(now, Location_Shearer);
                    e.Result = now + "煤机位置存储完成\r\n";
                }               
            }
        }


        public delegate void SetText(Label l,string txt);
        private void SetlbText(Label l,string txt)
        {
            l.Text = txt;
        }

        private void Btn_ReadConfig_Click(object sender, EventArgs e)
        {
            string str = "";
            var listsyR = SymbolConfig.GetSymbolADS(SymbolConfig.Flag_Direction.R);
            foreach(var sy in listsyR)
            {
                str = str + sy.SymbolADSName + "; ";
            }
            ResultAppendText(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss ") + str + "SymbolCount:" + listsyR.Count+" \r\n");
            str = "";
            var listsyL = SymbolConfig.GetSymbolADS(SymbolConfig.Flag_Direction.L);
            foreach (var sy in listsyL)
            {
                str = str + sy.SymbolADSName + "; ";
            }
            ResultAppendText(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss ") + str +"SymbolCount:"+ listsyL.Count + " \r\n");
        }

        private void ExitToolStripMenuItem_Click(object sender, EventArgs e)
        {
            isExit = true;
            Application.Exit();
        }



        public void SetLableText(Label l,string txt)
        {
            if (l.InvokeRequired)
            {
                this.Invoke(new SetText(SetlbText), l, txt);
            }
            else
            {
                SetlbText(l, txt);
            }
        }

        private void btnClearResult_Click(object sender, EventArgs e)
        {
            rhTxtResult.Clear();
        }
    }

}
